package com.xishu.controller;

import com.xishu.bo.DetailReport;
import com.xishu.config.Constant;
import com.xishu.entity.hardware.Printer;
import com.xishu.entity.oplog.OrderOpLog;
import com.xishu.entity.order.Order;
import com.xishu.entity.order.OrderItem;
import com.xishu.entity.shop.FoodTable;
import com.xishu.entity.shop.LineUp;
import com.xishu.entity.shop.Shop;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.ResponseData;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.CommonService;
import com.xishu.service.OrderOpLogService;
import com.xishu.service.order.base.OrderService;
import com.xishu.service.print.PrinterService;
import com.xishu.util.ClassUtil;
import com.xishu.util.ServletUtil;
import com.xishu.util.Tools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;

@RestController
@Api(description = "打印机服务")
public class PrinterServiceController implements Tools {
    private static Logger logger = LoggerFactory.getLogger(PrinterServiceController.class);
    private CommonService commonService = CommonService.getInstance();
    private PrinterService printerService = PrinterService.getInstance();
    private OrderService orderService = OrderService.getInstance();

    /**
     * 打印机是否正常
     *
     * @param printerOptional
     */
    private void isPrinterValid(Optional<Printer> printerOptional) throws ResponseStatusException {
        VerifyUtil.verify(() -> printerOptional.isPresent(), ResponseStatus.PRINTER_UNMORAL);
        Printer printer = printerOptional.get();

        //已经设置为下线了
        if (printer.getOnline() != null && !printer.getOnline()) {
            VerifyUtil.throwError(ResponseStatus.PRINTER_UNMORAL);
        }
    }

    /**
     * 打印机是否正常
     *
     * @param printerId
     */
    private void isPrinterValid(Long printerId) throws Exception {
        Optional<Printer> printerOptional = printerService.findPrinter(printerId);
        isPrinterValid(printerOptional);
    }


    @ApiOperation(value = "打印新开台的二维码")
    @PutMapping(value = ("/printer/add/new/order/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData printerAddNewOrder(@RequestBody FoodTable reqFoodTable, @PathVariable("printerId") Long printerId) throws Exception {
        //判断打印机的状态
        isPrinterValid(printerId);

        printerService.printerAddNewOrder(reqFoodTable, printerId);
        return ResponseData.emptyResponse();
    }

    @Deprecated
    @ApiOperation(value = "发送订单到厨房,本地测试使用")
    @PutMapping(value = ("/printer/send/to/kitchen"), produces = ("application/json;charset=UTF-8"))
    public ResponseData sendKitchen(@RequestBody Order reqOrder) throws Exception {
        Order order = OrderService.getInstance().findOrder(reqOrder.getShopId(), reqOrder.getId());
        printerService.sendOrderToKitchen(order, order.getPrinterId());
        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "打印小票")
    @PutMapping(value = ("/printer/order/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData printOrder(@RequestBody Order order, @PathVariable("printerId") Long printerId) throws Exception {
        try {
            //判断打印机的状态
            isPrinterValid(printerId);
            Order orderInDb = orderService.findOrder(order.getShopId(), order.getId());
            //换一个对象处理，以防止对象被自动提交了
            orderInDb = (Order) ClassUtil.clone(orderInDb);
            logger.info("print order is {}", orderInDb);

            //过滤已经审核通过的菜
            List<OrderItem> orderItemList = getList(orderInDb.getOrderItemDetailList()).stream().filter(orderItem -> getBoolean(orderItem.getCheckout()) && getBoolean(orderItem.getConfirmItem())).collect(Collectors.toList());
            orderInDb.setOrderItemDetailList(orderItemList);

            //因为这里一定是已经登录了，只用B端的价格
            orderService.showPrice(orderInDb, true);

            //没有结算完成的订单
            //如果有优惠券，先计算优惠券，然后再打印
            if (!equals(orderInDb.getStatus(), ORDER_STATUS_END) && isNotEmpty(order.getTicketCodeList())) {
                orderInDb.setTicketCodeList(order.getTicketCodeList());
                orderService.calPrice(orderInDb);
                ThreadContext.put(THREAD_LOCAL_VARIABLE_USE_USER_COST, "true");
            }

            if (getBoolean(orderInDb.getStripeTerminal())) {
                ThreadContext.put(THREAD_LOCAL_VARIABLE_PRINT_MERCHANT_COPY, "true");
            }

            printerService.printOrder(orderInDb, printerId, false, false);

            //打印账单，打印收据
            OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
            OrderOpLog orderOpLog = orderOpLogService.content(orderInDb, PRINT_ORDER);
            orderOpLogService.printOrderLog(orderInDb, orderOpLog);

            return ResponseData.emptyResponse();
        } finally {
            ThreadContext.remove(THREAD_LOCAL_VARIABLE_PRINT_MERCHANT_COPY);
            ThreadContext.remove(THREAD_LOCAL_VARIABLE_USE_USER_COST);
        }
    }

    @ApiOperation(value = "打印排队信息")
    @PutMapping(value = ("/printer/line/up/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData printLineUp(@RequestBody LineUp lineUp, @PathVariable("printerId") Long printerId) throws Exception {
        //判断打印机的状态
        isPrinterValid(printerId);

        String touchDeviceUUID = ServletUtil.getSessionAttribute(Constant.TOUCH_DEVICE_REDIS_KEY);
        printerService.printLineConfig(CommonService.getInstance().findEntity(lineUp.getId(), LineUp.class), printerId, touchDeviceUUID);
        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "打印闭店报告")
    @PutMapping(value = ("/printer/close/report/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData closeReport(@RequestBody Shop shop, @PathVariable("printerId") Long printerId) throws Exception {
        //判断打印机的状态
        isPrinterValid(printerId);

        String touchDeviceUUID = ServletUtil.getSessionAttribute(Constant.TOUCH_DEVICE_REDIS_KEY);
        printerService.printCloseReport(shop.getId(), printerId, touchDeviceUUID, null);
        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "打印详细的闭店报告")
    @PutMapping(value = ("/printer/detail/report/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData closeDetailReport(@RequestBody DetailReport detailReport, @PathVariable("printerId") Long printerId) throws Exception {
        //判断打印机的状态
        isPrinterValid(printerId);

        if (detailReport.getId() != null) {
            detailReport.setShopId(detailReport.getId());
        }

        VerifyUtil.verify(() -> detailReport.getShopId() != null);
        String touchDeviceUUID = ServletUtil.getSessionAttribute(Constant.TOUCH_DEVICE_REDIS_KEY);
        printerService.printCloseReport(detailReport.getShopId(), printerId, touchDeviceUUID, detailReport);
        return ResponseData.emptyResponse();
    }

    @ApiOperation(value = "分菜打印小票")
    @PutMapping(value = ("/printer/part/order/{printerId}"), produces = ("application/json;charset=UTF-8"))
    public ResponseData printPartFood(@RequestBody Order reqOrder, @PathVariable("printerId") Long printerId) throws Exception {
        //判断打印机的状态
        isPrinterValid(printerId);

        Long shopId = reqOrder.getShopId();
        Long orderId = reqOrder.getId();
        VerifyUtil.verify(() -> shopId != null);
        VerifyUtil.verify(() -> orderId != null);
        OrderService orderService = OrderService.getInstance();
        Order orderInDb = orderService.findOrder(shopId, orderId);
        orderInDb = (Order) ClassUtil.clone(orderInDb);
        orderInDb.setTicketCodeList(reqOrder.getTicketCodeList());

        //没有结账的时候，计算一下金额
        if (!getBoolean(orderInDb.getPayed())) {
            if (orderInDb.getUserSelectPayType() == USER_SELECT_PAY_TYPE_PART_CASH_CUSTOMIZED || orderInDb.getUserSelectPayType() == USER_SELECT_PAY_TYPE_PART_CASH_PER_PERSON) {
                orderService.calPrice(orderInDb, true);
            } else {
                orderService.calPrice(orderInDb, false);
            }

            orderInDb.setLeftCash(orderInDb.getUserCost());
        }

        //如果是已经支付完成的订单，那么找到该支付订单，并且只保留该订单的支付信息
        if (getBoolean(reqOrder.getPrinterCustomerSignature())) {
            Order payedOrder = orderService.findPayOrderWithSubOrderId(orderInDb).stream().filter(p -> getBoolean(p.getPayed()) && !getBoolean(p.getCancel())).findAny().get();
            Order clonePayedOrder = (Order) ClassUtil.clone(payedOrder);
            orderInDb = clonePayedOrder;
        }
        //打印订单，写入日志
        OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
        OrderOpLog orderOpLog = orderOpLogService.content(orderInDb, PRINT_ORDER);
        orderOpLogService.printOrderLog(orderInDb, orderOpLog);

        printerService.printOrder(orderInDb, printerId, false, reqOrder.getPrinterCustomerSignature());
        return ResponseData.emptyResponse();
    }

}
